package entity

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"reflect"
	"src/zeus/common"
	"src/zeus/msgdef"
	"strconv"
	"strings"

	"src/zeus/logger"
)

// Defs 所有的实体定义
type Defs struct {
	defs map[string]*Def //key=json的名称(name字段)
}

var inst *Defs

// GetDefs 获取实体定义信息
func GetDefs() *Defs {
	return inst
}

func initDefs() {
	inst = &Defs{
		defs: make(map[string]*Def),
	}

	inst.Init()
}
func LoadDef(filePath string) *Def {
	if strings.HasSuffix(filePath, ".json") {
		raw, err := os.ReadFile(filePath)
		if err != nil {
			logger.Error("read entity def file error ", err)
			return nil
		}

		jsonInfo := make(map[string]interface{})
		err = json.Unmarshal(raw, &jsonInfo)
		if err != nil {
			logger.Error("parse entity def file error ", err)
			return nil
		}

		def := newDef()
		if err := def.fill(jsonInfo); err != nil {
			logger.Error("fill def error ", err)
			return nil
		}

		return def
	}

	return nil
}

// Init 初始化文件定义结构
func (defs *Defs) Init() {
	err := filepath.Walk("../res/propdef/entitydef", func(path string, f os.FileInfo, err error) error {
		if f == nil {
			return nil
		}

		if f.IsDir() {
			return nil
		}

		if def := LoadDef(path); def != nil {
			defs.defs[def.Name] = def
		}

		return nil
	})

	if err != nil {
		logger.Error("walk entity def file error")
	}
}

// GetDef 获取一个entity定义
func (defs *Defs) GetDef(name string) *Def {
	d, ok := defs.defs[name]
	if !ok {
		return nil
	}

	return d
}

////////////////////////////////////////////////////////////////

// Def 独立的实体定义
type Def struct {
	Name        string
	TypeMap     map[string]uint8    //key=int8等类型str value=顺序
	IndexMap    map[string]uint16   //unused
	PropIndexs  map[uint16]*PropDef //unused
	Props       map[string]*PropDef //key=propName value
	ClientProps map[string]uint8
	NeedSubType map[string]bool //key=SubType value=服务器是否关心子类型
}

func newDef() *Def {
	return &Def{
		TypeMap:     make(map[string]uint8),
		IndexMap:    make(map[string]uint16),
		PropIndexs:  make(map[uint16]*PropDef),
		Props:       make(map[string]*PropDef),
		ClientProps: make(map[string]uint8),
		NeedSubType: make(map[string]bool),
	}
}

func (def *Def) fill(jsonmap map[string]interface{}) error {
	jsonInfo := common.JsonMap(jsonmap)
	def.Name = jsonInfo.GetString("name").String()
	// def.Name = jsonInfo["name"].(string)
	startIndex := jsonInfo.GetUInt16("startIndex")
	// startIndex := uint16(jsonInfo["startIndex"].(float64))

	jsonTypeMaps := jsonInfo.GetMap("typemap")
	jsonProps := jsonInfo.GetMap("props")
	jsonServers := jsonInfo.GetMap("server")
	var jsonClient common.JsonArray
	if _, ok := jsonInfo["client"]; ok {
		jsonClient = jsonInfo.GetMap("client").GetArrayIfExist("props")
	}

	// if !ok {
	// 	log.Error("读取客户端关注的属性失败!")
	// }
	jsonMRoleMap := jsonInfo.GetMap("mrole")
	// if !ok {
	// 	return fmt.Errorf("读取失败")
	// }
	jsonMRole, ok := jsonMRoleMap["props"].([]interface{})
	if !ok {
		logger.Error("读取主角关注的属性失败!")
	}
	for TypeName, TypeIndex := range jsonTypeMaps {
		def.TypeMap[TypeName] = uint8(TypeIndex.(float64))
	}

	indexMap := make(map[uint16]bool)
	for propName, propInfo := range jsonProps {
		jsonProp, ok := propInfo.(map[string]interface{})
		if !ok {
			logger.Error("jsonProp 格式有问题!", propName)
			return fmt.Errorf("item 读取失败")
		}
		fillPropInfo := func(propName string, jsonProp map[string]interface{}, isMain bool) error {
			index := uint16(jsonProp["index"].(float64))
			if _, ok := indexMap[index]; ok {
				logger.Error("item 属性index重复! ", index)
				return fmt.Errorf("item 读取失败")
			}

			index = startIndex + index
			typestr := jsonProp["type"].(string)
			prop := newPropDef()
			def.Props[propName] = prop
			prop.Name = propName
			prop.Index = index
			prop.IsMain = isMain
			prop.Desc = jsonProp["desc"].(string)
			prop.Type = def.getTypeByStr(jsonProp["type"].(string))
			prop.TypeName = typestr
			if strings.Contains(prop.TypeName, "*protoMsg") {
				prop.TypeName = prop.TypeName[10:]
				typestr = "protoMsg"
			} else if strings.Contains(prop.TypeName, "*ProtoMsg") {
				prop.TypeName = prop.TypeName[10:]
				typestr = "protoMsg"
			} else if strings.Contains(prop.TypeName, "protoMsg") {
				prop.TypeName = prop.TypeName[9:]
				typestr = "protoMsg"
			} else if strings.Contains(prop.TypeName, "ProtoMsg") {
				prop.TypeName = prop.TypeName[9:]
				typestr = "protoMsg"
			} else if sindex := strings.Index(prop.TypeName, "."); sindex != -1 {
				//找到了类型
				prop.TypeName = prop.TypeName[sindex+1:]
				typestr = "protoMsg"
			}
			typeIndex, ok := def.TypeMap[typestr]
			if !ok {
				logger.Error("item 类型定义失败! 无此类型！ ", jsonProp["type"].(string))
				return fmt.Errorf("item 读取失败")
			}
			prop.TypeIndex = typeIndex
			prop.SaveSrvType = 0
			if persistence, ok := jsonProp["save"].(string); ok {
				prop.SaveSrvType = uint8(common.NewStringAny(persistence).ToUint64V())
			}
			//如果save没有设置的时候，就需要设置这个属性了
			prop.MainSrvType = prop.SaveSrvType
			if v, ok := jsonProp["main"].(string); ok {
				prop.MainSrvType = uint8(common.NewStringAny(v).ToUint64V())
			}
			prop.Sync = true
			if sync, ok := jsonProp["sync"].(string); ok {
				if sync == "0" {
					prop.Sync = false
				}
			}
			for srvTypeName, srvInfo := range jsonServers {

				srvPropList, ok := srvInfo.(map[string]interface{})["props"].([]interface{})
				if !ok {
					logger.Error("分析服务器关心的属性列表失败", srvTypeName, srvInfo)
					continue
				}

				isInterest := false
				for _, srvPropName := range srvPropList {
					if srvPropName.(string) == propName {
						isInterest = true
						break
					}
				}

				if isInterest {
					srvType, _ := strconv.Atoi(srvTypeName)
					prop.InterestSrvs = append(prop.InterestSrvs, uint8(srvType))
				}
			}

			if json, ok := jsonInfo["subType"]; ok {
				//{"subType":     {"SubType1":{"props":["PropName1","PropName2",...]}, "subType2":{}}     }
				jsonSubTypes := json.(map[string]interface{})
				for subType, Info := range jsonSubTypes {
					def.NeedSubType[subType] = true
					subPropList, ok := Info.(map[string]interface{})["props"].([]interface{})
					if !ok {
						logger.Error("分析服务器关心的子类型属性列表失败", subType, Info)
						continue
					}

					isInterest := false
					for _, subPropName := range subPropList {
						if subPropName.(string) == propName {
							isInterest = true
							break
						}
					}

					if isInterest {
						prop.SubTypes[subType] = true
					}
				}
			}

			prop.IsClientInterest = false
			for _, clientProp := range jsonClient {
				if propName == clientProp.(string) {
					prop.IsClientInterest = true
					break
				}
			}

			prop.IsMRoleInterest = false
			for _, mroleProp := range jsonMRole {
				if propName == mroleProp.(string) {
					prop.IsMRoleInterest = true
					// modify by zgb 2019.09.27 下面这行代码，会导致gateway有玩家的所有属性，之前可能gate可能会需要这里做属性同步，
					// 但是现在应该没有了，而且我觉得也不应该有，先注释掉，有问题再修改
					// prop.InterestSrvs = append(prop.InterestSrvs, iserver.ServerTypeGateway)
					break
				}
			}
			return nil
		}

		if err := fillPropInfo(propName, jsonProp, true); err != nil {
			return err
		}
		if subProps, ok := jsonProp["sub"].(map[string]interface{}); ok {
			for subPropName, subPropInfo := range subProps {

				subJsonProp, ok := subPropInfo.(map[string]interface{})
				if !ok {
					logger.Error("subJsonProp 格式有问题!", subPropName)
					return fmt.Errorf("item 读取失败")
				}
				if err := fillPropInfo(subPropName, subJsonProp, false); err != nil {
					return err
				}
			}
		}
	}

	return nil
}

func (def *Def) getTypeByStr(st string) reflect.Type {

	var t reflect.Type

	switch st {
	case "int8":
		t = reflect.TypeOf(int8(0))
	case "int16":
		t = reflect.TypeOf(int16(0))
	case "int32":
		t = reflect.TypeOf(int32(0))
	case "int64":
		t = reflect.TypeOf(int64(0))
	case "byte":
		t = reflect.TypeOf(byte(0))
	case "uint8":
		t = reflect.TypeOf(uint8(0))
	case "uint16":
		t = reflect.TypeOf(uint16(0))
	case "uint32":
		t = reflect.TypeOf(uint32(0))
	case "uint64":
		t = reflect.TypeOf(uint64(0))
	case "float32":
		t = reflect.TypeOf(float32(0))
	case "float64":
		t = reflect.TypeOf(float64(0))
	case "string":
		t = reflect.TypeOf("")
	case "bool":
		t = reflect.TypeOf(false)
	default:
		return nil
	}

	return t
}

////////////////////////////////////////////////////////////////

// PropDef 字段定义
type PropDef struct {
	Name             string
	Index            uint16
	Desc             string
	Type             reflect.Type    //本数据的类型，可以使用它进行实例化，但都是基础类型，如果是struct的话，要使用TypeName进行Def管理器的反射
	TypeName         string          //反射注册来源是gcommon.ProtoMap,是一个工具生成的文件
	TypeIndex        uint8           //如果是特殊类型（common.Type_protoMsg），会使用CreateInst方法去 msgdef.GetMsgDef()拿到对应的新实例
	InterestSrvs     []uint8         //对此属性感兴趣的服务器,如果是其他服务器 可以同步给其他服务器.
	SubTypes         map[string]bool //还不知道有什么用，会用到这个东西的是Item.json里面
	IsClientInterest bool            //客户端AOI 广播属性(仅限 类型=3 Space/Instance 使用)
	IsMRoleInterest  bool            //客户端关注的属性
	SaveSrvType      uint8           //是否需要持久化, 默认true
	MainSrvType      uint8           // 管理这个属性的服务器,默认值同SaveSrv,可以为其他服务器来管理的.
	Sync             bool            //是否需要同步至其他服务器, 默认true
	IsMain           bool            //是否是主属性（主属性是指真正的属性，非主属性，指的是为了优化同步或者其他目的设置的临时属性，如一些update类的属性）
}

func newPropDef() *PropDef {
	return &PropDef{
		InterestSrvs: make([]uint8, 0, 5),
		SubTypes:     make(map[string]bool),
	}
}

// CreateInst 创建该属性的一个实例
func (pd *PropDef) CreateInst() (interface{}, error) {

	if pd.Type != nil {
		return reflect.New(pd.Type), nil
	}

	msgID, err := msgdef.GetMsgDef().GetMsgIDByName(pd.TypeName)
	if err != nil {
		return nil, err
	}

	_, msgContent, err := msgdef.GetMsgDef().GetMsgInfo(msgID)
	return msgContent, err
}

// IsValidValue 当前值是否能设置到该属性上
func (pd *PropDef) IsValidValue(value interface{}) bool {

	if value == nil {
		return true
	}

	if pd.Type != nil {
		return pd.Type == reflect.TypeOf(value)
	}

	return strings.Contains(reflect.TypeOf(value).String(), pd.TypeName)
}

func (pd *PropDef) String() string {
	bs, _ := json.Marshal(pd)
	return string(bs)
}
